import math

class Neuron:
	LEARNING_FACTOR = 0.1
	
	def __init__(self):
		self.__voltage = 0
		self.__inputs = {}
		
	def reset(self):
		self.__voltage = 0
		
	def getVoltage(self):
		return self.__voltage
		
	def setVoltage(self, voltage):
		self.__voltage = voltage
		
	def addInput(self, neuron, weight):
		self.__inputs[neuron] = weight
		
	def getInputs(self):
		return self.__inputs
		
	def run(self):
		inputSum = sum((neuron.getVoltage() * weight for (neuron, weight) in self.__inputs.items()))
		self.__voltage = 1 / (1 + math.exp(-inputSum))
		return self.__voltage
		
	def bp(self, expected):
		if len(self.__inputs) == 0:
			return
		output = self.__voltage
		outputDiff = expected - output
		if outputDiff == 0:
			return
		derivative = 1 / self.__voltage - 1
		inputDiff = outputDiff / derivative
		inputSum = -math.log(1 / self.__voltage - 1)
		if inputSum == 0:
			inputSum = 1
		for (neuron, weight) in self.__inputs.items():
			weight += Neuron.LEARNING_FACTOR * weight * inputDiff / inputSum
			if weight > 10:
				weight = 10
			if weight < -10:
				weight = -10
			self.__inputs[neuron] = weight
			neuron.bp(neuron.getVoltage() * weight)
